#include <bits/stdc++.h>

#define eb emplace_back
#define fi first
#define se second
#define in read()
#define rep(i, x, y) for(int i = (x); i <= (y); i++)
#define per(i, x, y) for(int i = (x); i >= (y); i--)

using namespace std;

using ll = long long;
using pii = pair < int, int >;
using vec = vector < int >;
using tl = tuple < int, int, int >;

int read() {
	int x = 0; bool f = 0; char ch = getchar();
	while(!isdigit(ch)) f |= ch == '-', ch = getchar();
	while(isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
	return f ? -x : x;
}

const int N = 1.5e6 + 10;
const int K = 21;

int n, cnt, ln;

struct graph {
	vector < tl > G[N];
	int fr[N << 2], to[N << 2], len[N << 2], cnt;
	bool v[N];
	void reset() { cnt = 1; rep(i, 1, n) G[i].clear(); }
	graph() { cnt = 1; }
	void link(int x, int y, int w) { cnt++; fr[cnt] = x; to[cnt] = y; len[cnt] = w; G[x].eb(y, w, cnt); }
	void alink(int x, int y, int w) { link(x, y, w); link(y, x, w); }
	bool& vis(int id) { return v[id / 2]; }
} g1, g2;

namespace L {
	const int N = 8e5 + 10;
	int stk[N], dep[N], tot, dfn[N], R[N], mn[K + 1][N], lg[N], pw[K + 10];
	ll tdep[N];
	void dfs(int x, int p) {
		stk[dfn[x] = R[x] = ++tot] = x; dep[x] = dep[p] + 1; int y, w, id;
		for(auto v : g2.G[x]) {
			tie(y, w, id) = v; if(y == p) continue;
			tdep[y] = tdep[x] + w; dfs(y, x); stk[R[x] = ++tot] = x; 
		}
	}
	inline int tmn(int x, int y) { return dep[x] < dep[y] ? x : y; }
	inline int LCA(int x, int y) { if(dfn[x] > dfn[y]) swap(x, y); x = dfn[x]; y = R[y]; int k = lg[y - x + 1]; return tmn(mn[k][x], mn[k][y - pw[k] + 1]); }
	void build() {
		dfs(1, 0); rep(i, 2, tot) lg[i] = lg[i >> 1] + 1;
		pw[0] = 1; rep(i, 1, K) pw[i] = pw[i - 1] * 2;
		rep(i, 1, tot) mn[0][i] = stk[i];
		rep(i, 1, K)
			rep(j, 1, tot - pw[i] + 1)
			mn[i][j] = tmn(mn[i - 1][j], mn[i - 1][j + pw[i - 1]]);
	}
}

namespace transmap {
	void dfs(int x, int p) {
		for(auto v : g1.G[x]) {
			int y, w, id; tie(y, w, id) = v;
			if(y == p) continue; g2.link(x, y, w); dfs(y, x);
		}
	}
	void rebuild() {
		dfs(1, 0); int y, w, id; g1.reset();
		rep(x, 1, n) {
			if(g2.G[x].size() <= 2) {
				for(auto v : g2.G[x]) {
					tie(y, w, id) = v; g1.alink(x, y, w);
				}
			} else {
				int t1 = ++n, t2 = ++n;
				g1.alink(x, t1, 0); g1.alink(x, t2, 0);
				for(auto v : g2.G[x]) {
					tie(y, w, id) = v;
					if(g2.G[t1].size() < g2.G[t2].size()) g2.link(t1, y, w);
					else g2.link(t2, y, w);
				}
			}
		}
		g2.reset();
	}
}

int siz[N];
int rt, res;
ll ans = -1e18, dep[N], val[N], dis[N];
int tg[N];

void dfs(int x, int p) { int y, w, id; for(auto v : g1.G[x]) { tie(y, w, id) = v; if(y == p) continue; dep[y] = dep[x] + w; dfs(y, x); } }

void getrt(int x, int p, int tsiz) {
	siz[x] = 1; int y, w, id;
	for(auto v : g1.G[x]) {
		tie(y, w, id) = v; if(g1.vis(id) || y == p) continue;
		getrt(y, x, tsiz); siz[x] += siz[y];
		int mx = max(tsiz - siz[y], siz[y]);
		if(mx < res) res = mx, rt = id;
	}
}

namespace virtual_tree {
	vector < pair < int, ll > > G[N >> 2];
	int stk[N >> 2], top;
	void link(int x, int y) { G[x].eb(y, L :: tdep[y] - L :: tdep[x]); }
	pair < ll, ll > dfs(int x, const int &exw) {
		pair < ll, ll > res; res.fi = -1e18; res.se = -1e18; int y; ll w;
		if(tg[x] == 1) res.fi = val[x]; if(tg[x] == 2) res.se = val[x];
		for(auto v : G[x]) {
			tie(y, w) = v;
			auto t = dfs(y, exw);
			ans = max(ans, (res.fi + t.se + exw) / 2 - L :: tdep[x]);
			ans = max(ans, (res.se + t.fi + exw) / 2 - L :: tdep[x]);
			res.fi = max(res.fi, t.fi); res.se = max(res.se, t.se);
		} return res;
	}
	void cdfs(int x) { tg[x] = 0; for(auto v : G[x]) cdfs(v.fi); vector < pair < int, ll > >().swap(G[x]); }
	void solve(const vec &pot, const int &exw) {
		stk[top = 1] = 1;
		for(auto x : pot) {
			if(x == 1) continue;
			int lca = L :: LCA(stk[top], x);
			while(top > 1 && L :: dep[lca] <= L :: dep[stk[top - 1]]) link(stk[top - 1], stk[top]), top--;
			if(top && lca != stk[top]) link(lca, stk[top]), stk[top] = lca;
			stk[++top] = x;
		}
		rep(i, 2, top) link(stk[i - 1], stk[i]);
		dfs(1, exw); cdfs(1);
	}
}

void calc(int x, int p) {
	int y, w, id;
	for(auto v : g1.G[x]) {
		tie(y, w, id) = v; if(g1.vis(id) || y == p) continue;
		dis[y] = dis[x] + w; calc(y, x);
	}
}

vec divide(int x, int tsiz) {
	rt = 0; res = 1e9; getrt(x, 0, tsiz); 
	if(res == 1e9) return x > ln ? vec() : vec(1, x);
	vec pot;
	int id = rt; g1.vis(id) = true; int y = g1.to[rt], exw = g1.len[rt]; x = g1.fr[rt];
	if(siz[x] > siz[y]) swap(x, y);
	int asz = siz[x], bsz = tsiz - asz;
	vec t1 = divide(x, asz), t2 = divide(y, bsz);
	for(auto v : t1) tg[v] = 1; for(auto v : t2) tg[v] = 2;
	auto it1 = t1.begin(), it2 = t2.begin();
	while(it1 != t1.end() && it2 != t2.end()) {
		if(L :: dfn[*it1] < L :: dfn[*it2]) pot.eb(*it1), it1++;
		else pot.eb(*it2), it2++;
	}
	while(it1 != t1.end()) pot.eb(*it1), it1++;
	while(it2 != t2.end()) pot.eb(*it2), it2++;
	dis[x] = dis[y] = 0; calc(x, 0); calc(y, 0);
	for(auto v : pot) val[v] = dep[v] + dis[v];
	virtual_tree :: solve(pot, exw); g1.vis(id) = 0;
	return pot;
}

signed main() {
#ifndef ONLINE_JUDGE
	freopen("1.in", "r", stdin);
#endif
	ln = n = in;
	rep(i, 2, n) { int u = in, v = in, w = in; g1.alink(u, v, w); }
	transmap :: rebuild();
	rep(i, 2, ln) { int u = in, v = in, w = in; g2.alink(u, v, w); }
	L :: build(); dfs(1, 0); divide(1, n); rep(i, 1, ln) ans = max(ans, dep[i] - L :: tdep[i]); printf("%lld\n", ans);
	return 0;
}
